﻿using System.Buffers;
using System.Net;
using System.Reflection;
using System.Text;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Server.Packet;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Kcp.KcpSharp;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Util;
using Google.Protobuf;
using Google.Protobuf.Reflection;

namespace EggLink.DanhengServer.GameServer.Server;

/// <summary>
/// 表示游戏服务器与客户端的连接
/// </summary>
public class Connection (KcpConversation conversation, IPEndPoint remote) : DanhengConnection(conversation, remote)
{
    private static readonly Logger Logger = new("GameServer");

    /// <summary>
    /// 获取或设置与此连接关联的玩家实例
    /// </summary>
    public PlayerInstance? Player { get; set; }

    /// <summary>
    /// 启动连接处理
    /// </summary>
    public override async void Start ()
    {
        Logger.Info($"新连接来自 {RemoteEndPoint}。");
        State = SessionStateEnum.WAITING_FOR_TOKEN;
        await ReceiveLoop();
    }

    /// <summary>
    /// 停止连接并清理资源
    /// </summary>
    public override void Stop ()
    {
        Player?.OnLogoutAsync();
        DanhengListener.UnregisterConnection(this);
        base.Stop();
    }

    /// <summary>
    /// 接收消息循环
    /// </summary>
    protected async Task ReceiveLoop ()
    {
        while (!CancelToken.IsCancellationRequested)
        {
            // 等待接收消息或连接关闭
            var result = await Conversation.WaitToReceiveAsync(CancelToken.Token);
            if (result.TransportClosed)
            {
                Logger.Debug("连接已关闭");
                break;
            }

            if (result.BytesReceived > MAX_MSG_SIZE)
            {
                Logger.Error("数据包过大");
                Conversation.SetTransportClosed();
                break;
            }

            var buffer = ArrayPool<byte>.Shared.Rent(result.BytesReceived);
            try
            {
                if (!Conversation.TryReceive(buffer, out result))
                {
                    Logger.Error("接收数据包失败");
                    break;
                }

                await ProcessMessageAsync(buffer.AsMemory(0, result.BytesReceived));
            }
            catch (Exception ex)
            {
                Logger.Error("数据包解析错误", ex);
            }
            finally
            {
                ArrayPool<byte>.Shared.Return(buffer);
            }
        }

        Stop();
    }

    /// <summary>
    /// 处理接收到的游戏数据包
    /// </summary>
    /// <param name="data">接收到的数据</param>
    private async Task ProcessMessageAsync (Memory<byte> data)
    {
        var gamePacket = data.ToArray();
        if (ConfigManager.Config.GameServer.UsePacketEncryption)
            Crypto.Xor(gamePacket, XorKey!);

        await using MemoryStream ms = new(gamePacket);
        using BinaryReader br = new(ms);

        try
        {
            while (br.BaseStream.Position < br.BaseStream.Length)
            {
                // 数据包完整性检查
                if (br.BaseStream.Length - br.BaseStream.Position < 12) return;

                var magic1 = br.ReadUInt32BE();
                if (magic1 != 0x9D74C714)
                {
                    Logger.Error($"收到错误的数据包: 收到 0x{magic1:X}, 应为 0x9D74C714");
                    return;
                }

                // 解析数据包
                var opcode = br.ReadUInt16BE();
                var headerLength = br.ReadUInt16BE();
                var payloadLength = br.ReadUInt32BE();
                var header = br.ReadBytes(headerLength);
                var payload = br.ReadBytes((int)payloadLength);

                LogPacket("接收", opcode, payload);
                await HandlePacket(opcode, header, payload);
            }
        }
        catch (Exception e)
        {
            Logger.Error(e.Message, e);
        }
    }

    /// <summary>
    /// 处理特定操作码的数据包
    /// </summary>
    /// <param name="opcode">操作码</param>
    /// <param name="header">数据包头</param>
    /// <param name="payload">数据包内容</param>
    private async Task HandlePacket (ushort opcode, byte[] header, byte[] payload)
    {
        var handler = HandlerManager.GetHandler(opcode);
        if (handler != null)
        {
            // 检查会话状态是否允许处理该数据包
            var state = State;
            switch (opcode)
            {
                case CmdIds.PlayerGetTokenCsReq:
                {
                    if (state != SessionStateEnum.WAITING_FOR_TOKEN) return;
                    goto default;
                }
                case CmdIds.PlayerLoginCsReq:
                {
                    if (state != SessionStateEnum.WAITING_FOR_LOGIN) return;
                    goto default;
                }
                default:
                    break;
            }

            try
            {
              
                await handler.OnHandle(this, header, payload);
            }
            catch
            {
                // 处理失败时构造错误响应
                var curPacket = LogMap.GetValueOrDefault(opcode);
                if (curPacket == null) return;

                var rspName = curPacket.Replace("Cs", "Sc").Replace("Req", "Rsp");
                if (rspName == curPacket) return;
                var rspOpcode = LogMap.FirstOrDefault(x => x.Value == rspName).Key;

                // 通过反射创建响应对象
                var typ = AppDomain.CurrentDomain.GetAssemblies()
                    .SingleOrDefault(assembly => assembly.GetName().Name == "DanhengProto")!.GetTypes()
                    .First(t => t.Name == rspName);
                var curTyp = AppDomain.CurrentDomain.GetAssemblies()
                    .SingleOrDefault(assembly => assembly.GetName().Name == "DanhengProto")!.GetTypes()
                    .First(t => t.Name == curPacket);

                if (Activator.CreateInstance(typ) is not IMessage rsp) return;

                // 设置错误码
                var retCode = typ.GetProperty("Retcode");
                retCode?.SetValue(rsp, (uint)Retcode.RetFail);

                // 复制请求中的相关字段到响应
                var descriptor =
                    curTyp.GetProperty("Descriptor", BindingFlags.Public | BindingFlags.Static)?.GetValue(
                        null, null) as MessageDescriptor;
                var reqPacket = descriptor?.Parser.ParseFrom(payload);

                foreach (var propertyInfo in curTyp.GetProperties())
                {
                    var prop = typ.GetProperty(propertyInfo.Name);
                    if (prop != null && prop.CanWrite)
                    {
                        var value = propertyInfo.GetValue(reqPacket);
                        if (value != null)
                            prop.SetValue(rsp, value);
                    }
                }

                // 发送错误响应
                var packet = new BasePacket((ushort)rspOpcode);
                packet.SetData(rsp);
                await SendPacket(packet);
            }

            return;
        }

        // 未找到处理器时自动构造响应
        var packetName = LogMap.GetValueOrDefault(opcode);
        if (packetName == null) return;

        var respName = packetName.Replace("Cs", "Sc").Replace("Req", "Rsp");
        if (respName == packetName) return;
        var respOpcode = LogMap.FirstOrDefault(x => x.Value == respName).Key;

        await SendPacket(respOpcode);
    }
}